package com.smasher.net.http

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import com.smasher.net.help.Confucius
import com.smasher.net.help.TokenManager
import com.smasher.net.http.authorization.AuthorizationStrategy
import com.smasher.net.http.authorization.BearerTokenStrategy
import com.smasher.net.http.convert.ConverterFactory
import com.smasher.net.http.convert.GsonConverterFactory
import com.smasher.net.http.convert.KotlinConverterFactory
import com.smasher.net.util.NetworkUtil
import okhttp3.Cache
import okhttp3.CacheControl
import okhttp3.Interceptor
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.ResponseBody.Companion.toResponseBody
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import java.io.File
import java.util.concurrent.TimeUnit

class HttpUtil private constructor() {

    @SuppressLint("StaticFieldLeak")
    private object SingletonHolder {
        val holder = HttpUtil()
    }

    private var initialized = false

    private var debugLog = false

    private lateinit var cache: Cache

    private lateinit var retrofitMain: Retrofit

    private lateinit var retrofitGson: Retrofit

    private lateinit var retrofitKotlin: Retrofit

    private var httpContext: Context? = null

    // 引入 AuthorizationStrategy 接口
    private var authorizationStrategy: AuthorizationStrategy = BearerTokenStrategy()

    // 引入 ConverterFactory 实例
    private var factory: ConverterFactory = GsonConverterFactory()

    // 定义多种缓存策略
    private val strictCacheControl = CacheControl.Builder()
        .onlyIfCached()
        .maxStale(2, TimeUnit.DAYS)
        .build()

    private val lenientCacheControl = CacheControl.Builder()
        .onlyIfCached()
        .maxStale(7, TimeUnit.DAYS)
        .build()

    private val noCacheControl = CacheControl.Builder()
        .noCache()
        .build()

    private val commonControl = CacheControl.Builder()
        .maxAge(60, TimeUnit.SECONDS)//缓存最大有效时间（秒）
        .build()

    /**
     * 云端响应头拦截器，用来配置缓存策略
     * Dangerous interceptor that rewrites the server's cache-control header.
     */
    private val mRewriteCacheControlInterceptor = Interceptor { chain: Interceptor.Chain ->
        val request = chain.request()
        val newRequest: Request
        if (!NetworkUtil.isNetworkAvailable(httpContext)) {
            newRequest = request.newBuilder()
                .cacheControl(strictCacheControl)
                .removeHeader(HEADER_PRAGMA)
                .build()
            if (debugLog) {
                Log.i(TAG, "no network,using cache strategy: $strictCacheControl")
            }
        } else {

            // 根据请求路径或标签选择不同的缓存策略
            val cacheStrategy = getCacheStrategy(request)
            val token = TokenManager.instance.getToken() ?: ""
            newRequest = request.newBuilder()
                .cacheControl(cacheStrategy)
                // 使用当前的授权策略来设置 Authorization 头
                .header(
                    authorizationStrategy.getAuthorizationHeaderName(),
                    authorizationStrategy.getAuthorizationHeader(token)
                )
                .removeHeader(HEADER_PRAGMA)
                .build()
        }
        chain.proceed(newRequest)
    }

    private fun getCacheStrategy(request: Request): CacheControl {
        return commonControl
    }

    private val mLoggingInterceptor = Interceptor { chain: Interceptor.Chain ->
        val request = chain.request()
        val t1 = System.nanoTime()
        val method = request.method
        if (debugLog) {
            Log.i(
                TAG,
                String.format(
                    "Sending %s request %s on %s%n%s",
                    method,
                    request.url,
                    chain.connection(),
                    request.headers
                )
            )
        }

        val response = chain.proceed(request)
        val t2 = System.nanoTime()
        if (debugLog) {
            Log.i(
                TAG,
                String.format(
                    "Received response for %s in %.1fms%n%s",
                    response.request.url,
                    (t2 - t1) / 1e6,
                    response.headers
                )
            )
        }

        var mediaType: MediaType? = null
        var resp = ""
        if (response.body != null) {
            mediaType = response.body?.contentType()
            resp = response.body?.string() ?: ""
            if (debugLog) {
                Log.d(TAG, resp)
            }

        }
        response.newBuilder()
            .body(resp.toResponseBody(mediaType))
            .build()
    }

    private val okHttpClient: OkHttpClient by lazy {
        OkHttpClient.Builder()
            .cache(cache)
            .connectTimeout(5, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .addInterceptor(mRewriteCacheControlInterceptor)
            .addInterceptor(mLoggingInterceptor)
            .build()
    }


    /**
     * 初始化
     * @param context Context
     */
    fun initWithCache(context: Context, cacheSize: Long = DEFAULT_CACHE_SIZE) {
        httpContext = context
        val file = File(context.cacheDir, "HttpCache")
        cache = Cache(file, cacheSize)
        createRetrofit()
        initialized = true
    }

    fun setDebug(debug: Boolean) {
        debugLog = debug
    }

    /**
     * 更新
     * 主要用于baseUrl变更
     */
    fun update() {
        checkInitialized()
        createRetrofit()
    }

    private fun checkInitialized() {
        if (!initialized) {
            throw IllegalStateException("请先初始化")
        }
    }


    private fun createRetrofit() {
        retrofitMain = Retrofit.Builder()
            .baseUrl(Confucius.suffixPro)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(factory.createFactory())
            .client(okHttpClient)
            .build()

        retrofitGson = Retrofit.Builder()
            .baseUrl(Confucius.suffixPro)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory().createFactory())
            .client(okHttpClient)
            .build()

        retrofitKotlin = Retrofit.Builder()
            .baseUrl(Confucius.suffixPro)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(KotlinConverterFactory().createFactory())
            .client(okHttpClient)
            .build()
    }

    fun <T> create(service: Class<T>): T {
        checkInitialized()
        return retrofitMain.create(service)
    }

    fun <T> createWithGson(service: Class<T>): T {
        checkInitialized()
        return retrofitGson.create(service)
    }

    fun <T> createWithKotlin(service: Class<T>): T {
        checkInitialized()
        return retrofitKotlin.create(service)
    }

    // 提供一个方法来设置当前的授权策略
    fun setAuthorizationStrategy(strategy: AuthorizationStrategy) {
        checkInitialized()
        this.authorizationStrategy = strategy
    }

    fun setConverterFactory(factory: ConverterFactory) {
        checkInitialized()
        this.factory = factory
    }

    fun release() {
        httpContext = null
    }

    companion object {

        private const val TAG = "HttpUtil"

        private const val HEADER_PRAGMA = "Pragma"
        private const val DEFAULT_CACHE_SIZE = (1024 * 1024 * 100).toLong()

        @JvmStatic
        fun getInstance(): HttpUtil {
            return SingletonHolder.holder
        }
    }
}